# @Time : 2020/6/25 15:14
# @Author : Fioman 
# @Phone : 13149920693
"""
除了用户定义的函数,调用运算符(即())还可以应用到其他对象上.如果想判断对象能否调用,可以使用内置的callable()函数.Python数据模型文档列出了7种可调用对象.
1> 用户定义的函数
    使用def语句或者lambda表达式创建
2> 内置函数
    使用C语言(CPython)实现的函数,如len或time.strtime.
3> 内置方法
    使用C语言实现的方法,如dict.get
4> 方法
    在内的定义体中定义的函数
5> 类
    调用类()会运行类的__new__方法创建一个实例,然后运行__init__方法,初始化实例,最后把实例返回给调用方.
6> 类的实例
    如果定义了__call__方法,那么它的实例可以作为函数调用
7> 生成器函数
    使用yield关键字的函数或方法.调用生成器函数返回的是生成器对象.
"""

obj1 = abs
obj2 = str
obj3 = 13
print("callable: obj1:{},obj2:{},obj3:{}".format(callable(obj1), callable(obj2), callable(obj3)))
"""
1> 不仅Python函数是真正的对象,任何Python对象都可以表现得像函数.为此,只要实现了实例方法__call__
当一个实例对象可以被当成函数来调用的时候(),这个时候其实实际上是调用了此对象的__call__方法.
"""
import random

class BingoCafe(object):
    def __init__(self,items):
        self._items = list(items)
        random.shuffle(self._items) # 打乱self._items的顺序

    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError("pick from empty BingoCafe")

    def __call__(self):
        return self.pick()


bingo = BingoCafe(range(20))
print("bingo.pick() = {}".format(bingo.pick()))

a = bingo()
print("bingo() = {}".format(a))

print("bingo callable = {}".format(callable(bingo)))























